﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Think.Problems;

namespace Think.Test.Problems
{
    [TestClass]
    public class CardTest
    {
        [TestMethod]
        public void ValidateValidCards()
        {
            // Execute
            var result = Card.Cards().All(Card.IsValid);

            // Assert
            Assert.IsTrue(result);
        }

        [TestMethod]
        public void ValidateNullCard()
        {
            // Execute
            var result = Card.IsValid(null);

            Assert.IsFalse(result);
        }

        [TestMethod]
        public void GetColorOfHeartsCard()
        {
            // Execute
            var result = Card.Color("AH");

            // Assert
            Assert.AreEqual(CardColor.Red, result);
        }

        [TestMethod]
        public void GetColorOfDiamonsCard()
        {
            // Execute
            var result = Card.Color("3D");

            // Assert
            Assert.AreEqual(CardColor.Red, result);
        }

        [TestMethod]
        public void GetColorOfClubCard()
        {
            // Execute
            var result = Card.Color("KC");

            // Assert
            Assert.AreEqual(CardColor.Black, result);
        }

        [TestMethod]
        public void GetColorOfSpadeCard()
        {
            // Execute
            var result = Card.Color("QC");

            // Assert
            Assert.AreEqual(CardColor.Black, result);        
        }

        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void GetColorOfInvalidCard()
        {
            // Execute
            var result = Card.Color("");
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void GetColorOfNullCard()
        {
            // Execute
            Card.Color(null);
        }

        [TestMethod]
        public void GetSuitOfClubCard()
        {
            // Execute
            var result = Card.Suit("4C");

            // Assert
            Assert.AreEqual(CardSuit.Club, result);
        }

        [TestMethod]
        public void GetSuitOfDiamondCard()
        {
            // Execute
            var result = Card.Suit("8D");

            // Assert
            Assert.AreEqual(CardSuit.Diamond, result);
        }

        [TestMethod]
        public void GetSuitOfHeartCard()
        {
            // Execute
            var result = Card.Suit("10H");

            // Assert
            Assert.AreEqual(CardSuit.Heart, result);
        }

        [TestMethod]
        public void GetSuitOfSpadeCard()
        {
            // Execute
            var result = Card.Suit("AS");

            // Assert
            Assert.AreEqual(CardSuit.Spade, result);
        }

        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void GetSuitOfInvalidCard()
        {
            // Execute
            var result = Card.Suit("Meow");
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void GetSuitOfNullCard()
        {
            // Execute
            var result = Card.Suit(a_card:null);
        }

        [TestMethod]
        public void GetRankValueOfCards()
        {
            // Setup
            var values = new[]
            {
                1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
                1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
                1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
                1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
            };

            // Execute
            var results = Card.Cards().Select(Card.RankValue).ToArray();

            // Assert
            CollectionAssert.AreEqual(values, results);
        }

        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void GetRankValueOfInvalidCard()
        {
            Card.RankValue("What does the fox say?");
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void GetRankOfNullCard()
        {
            Card.RankValue(a_card: null);
        }

        [TestMethod]
        public void GetAllCards()
        {
            // Setup
            var cards = new[] 
            {
                "AH", "2H", "3H", "4H", "5H", "6H", "7H", "8H", "9H", "10H", "JH", "QH", "KH",
                "AS", "2S", "3S", "4S", "5S", "6S", "7S", "8S", "9S", "10S", "JS", "QS", "KS",
                "AC", "2C", "3C", "4C", "5C", "6C", "7C", "8C", "9C", "10C", "JC", "QC", "KC",
                "AD", "2D", "3D", "4D", "5D", "6D", "7D", "8D", "9D", "10D", "JD", "QD", "KD",
            };

            // Execute
            var result = Card.Cards();

            // Assert
            CollectionAssert.AreEquivalent(cards, result);
        }

        [TestMethod]
        public void GetCardForSuit()
        {
            // Setup
            var cards = new[] 
            {
                "AC", "2C", "3C", "4C", "5C", "6C", "7C", "8C", "9C", "10C", "JC", "QC", "KC",
            };

            // Execute
            var result = Card.Cards(CardSuit.Club);

            // Assert
            CollectionAssert.AreEquivalent(cards, result);
        }

        [TestMethod]
        public void GetCardForSuitAndRank()
        {
            // Setup
            var suits = (CardSuit[])Enum.GetValues(typeof (CardSuit));
            var cards = new[] 
            {
                "AH", "2H", "3H", "4H", "5H", "6H", "7H", "8H", "9H", "10H", "JH", "QH", "KH",
                "AS", "2S", "3S", "4S", "5S", "6S", "7S", "8S", "9S", "10S", "JS", "QS", "KS",
                "AC", "2C", "3C", "4C", "5C", "6C", "7C", "8C", "9C", "10C", "JC", "QC", "KC",
                "AD", "2D", "3D", "4D", "5D", "6D", "7D", "8D", "9D", "10D", "JD", "QD", "KD",
            };

            var results = new List<String>();
            foreach (var suit in suits)
            {
                for (int i = 1; i <= 13; i++)
                    results.Add(Card.Create(suit, i));
            }

            // Assert
            CollectionAssert.AreEquivalent(cards, results);
        }

        [TestMethod]
        public void GetCardsForRank()
        {
            // Setup
            var suits = (CardSuit[])Enum.GetValues(typeof(CardSuit));
            var cards = new[] { "6H", "6S", "6C", "6D" };

            var result = Card.Cards(6);

            CollectionAssert.AreEquivalent(cards, result);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void GetCardForSuitAndZeroRank()
        {
            // Execute
            var result = Card.Create(CardSuit.Heart, 0);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void GetCardForSuitAndNegativeRank()
        {
            // Execute
            var result = Card.Create(CardSuit.Diamond, -10);
        }


        [TestMethod]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void GetCardForSuitAndRankOutOfRange()
        {
            // Execute
            var result = Card.Create(CardSuit.Diamond, 14);
        }

    }
}
